package com.baosight.qualitycontrol.util;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONArray;

public class MathUtil {
	private static final Logger log = LoggerFactory.getLogger(MathUtil.class);
	
	public static int PRECISION_STEP = 1;
	
	public static double round(double value, int scale) {
		return new BigDecimal(value).setScale(scale, RoundingMode.HALF_UP).doubleValue();
	}
	
    public static double[] jsonArrayToDoubleArray(JSONArray jsonArray) {
        double[] result = new double[jsonArray.size()];
        for(int i=0; i<jsonArray.size(); i++) {
            result[i] = jsonArray.getDouble(i);
        }
        return result;
    }

    public static <T> T[] listToArray(List<T> list, T[] t) {
        for(int i=0; i<list.size(); i++) {
            t[i] = list.get(i);
        }
        return t;
    }
    
    public  static int contains(List<Double> res, double sample) {
        if (sample < res.get(0)) return -2;
        int i = 0;
        while (sample > res.get(i)){

            if (i+1 >= res.size()) break;
            i++;
        }
        if (i < res.size()-1 || sample < res.get(res.size()-1)) return i;
        return -1;
    }
    
    public static int getMaxValueIndex(Double[] array) {
        double tmp = array[0];
        int index = 0;
        for(int i=0; i<array.length; i++) {
            if (array[i] > tmp) {
                index = i;
                tmp = array[i];
            }
        }
        return index;
    }
	
    /**
     * @param resYValue 纵坐标
     * @param resXValue 横坐标
     * @param precision 精度
     * @return
     */
    public static double[] newtonInterpolation2(double[] resYValue, double[] resXValue, double precision) {

        long start = System.currentTimeMillis();
        List<Double> resYList = new ArrayList<>();
        List<Double> resXList = new ArrayList<>();
//        Double minValue = utilService.limitValue(resXList);

        // 有效数据长度
        int m = 0;
        // 统一数据长度
        Double[] xs = Arrays.stream(resXValue).mapToObj(Double::new).toArray(Double[]::new);
        Double[] ys = Arrays.stream(resYValue).mapToObj(Double::new).toArray(Double[]::new);

        int count = 0;
        for (int i = 0; i < xs.length; i++) {
            if (xs[i] > 10000) count++;
            else break;
        }
        Double[] newx = Arrays.stream(xs).skip(count).toArray(Double[]::new);
        Double[] newy = Arrays.stream(ys).skip(count).toArray(Double[]::new);
        int minLength = Math.min(newx.length, newy.length);


        int maxIndex = getMaxValueIndex(newx);

        for (int v = 0; v < minLength; v++) {
            // 过滤掉位置变量为0的点
//            if (resXValue[v] < 0.01 || v > maxIndex) {
//                continue;
//            }
            if (newx[v] < 0.01 || v > maxIndex) {
                continue;
            }
            if (v > 0 && (newx[v] <= newx[v - 1])) {
                continue;
            }
//            resY[m] = resYValue[v];
            resYList.add(newy[v]);
//            resX[m] = resXValue[v];
            resXList.add(newx[v]);
            m++;
        }
        Double[] resY = new Double[m];
        Double[] resX = new Double[m];
        // 有效X数据
        resX = listToArray(resXList, resX);
//        int count = 0;
//        for (int i = 0; i < resX_1.length; i++) {
//            if(resX_1[i] > 10000) count++;
//            else break;
//        }
//        Double[] resX = Arrays.stream(resX_1).skip(count).toArray(Double[]::new);

        //由于位置曲线x 数采单位不一 若是大的即除以1000 若是正常的即不做处理
        if (resX[resX.length - 1] > 2000) {
            BigDecimal bigDecimal1000 = new BigDecimal(1000);
            for (int i = 0; i < resX.length; i++) {
                BigDecimal bigDecimal1 = new BigDecimal(resX[i]);
                double value = bigDecimal1.divide(bigDecimal1000, 6, RoundingMode.HALF_UP).doubleValue();
                resX[i] = value;
            }
        }
        // 有效Y数据
        resY = listToArray(resYList, resY);

        //删除长度点第一个数据
//        m = m - count;
        if (m < 1) return new double[0];

//        long start = System.currentTimeMillis();

        // 结束x值
        double endP = resX[m - 1];
        // 开始x值
        double startP = resX[0];
        // 最大X值
        double maxP = Math.max(endP, startP);
        double minP = Math.min(endP, startP);

        // 正向还是反向
        if (startP > endP) precision = -precision;

        // 保存返回的点位置
        double[] desX = new double[(int) Math.abs((maxP - minP) / precision)];

        double p = precision < 0 ? maxP : minP;

        for (int k = 0; k < desX.length; k++) {
            desX[k] = p;
            p += precision;
            if ((precision > 0 && p >= maxP) || (precision < 0 && p < minP)) break;
        }

        if (precision < 0) {
            ArrayUtils.reverse(resX);
            ArrayUtils.reverse(resY);
            ArrayUtils.reverse(desX);
        }

        List<Double> desY = new ArrayList();

        List<List<Double>> containerX = new ArrayList<>();
        List<List<Double>> containerY = new ArrayList<>();
        // 将原始曲线每5个点分成一段
        for (int ct = 0; ct < resX.length / PRECISION_STEP + 1; ct++) {
//            Double[] xTmp = new Double[6];
//            Double[] yTmp = new Double[6];
            List<Double> xTmp = new ArrayList<>();
            List<Double> yTmp = new ArrayList<>();
            int k1 = ct * PRECISION_STEP;
            int k2 = 0;
            while (k1 < resX.length && k2 < PRECISION_STEP) {
                xTmp.add(resX[k1]);
                yTmp.add(resY[k1]);
                k2++;
                k1++;
            }
            // 2个container之间重合一个点
            if (k1 < resX.length) {
                xTmp.add(resX[k1]);
                yTmp.add(resY[k1]);
            }
            containerX.add(xTmp);
            containerY.add(yTmp);
        }

//        for(int dx=0; dx<desX.length; dx++) {
        int idx = 0;
        int calcNum = 0;

        for (int ct = 0; ct < containerX.size(); ct++) {
            List<Double> cerX1 = containerX.get(ct);
            //去重，避免在牛顿算法分母为0
            List<Double> cerX = cerX1.stream().distinct().collect(Collectors.toList());

            if (cerX == null || cerX.size() < 1) continue;

            List<Double> tmpDesX = new ArrayList<>();
//            int i = 0;
            // 将目标X轴数值按照 原始曲线的区分，进行分组，差值
            while (idx < desX.length) {
                if (contains(cerX, desX[idx]) != -1) {
                    tmpDesX.add(desX[idx]);
                    idx++;
                } else break;

            }
            calcNum += tmpDesX.size();
            if (tmpDesX.size() > 0) {
                Double[] tmpDesXArray = new Double[tmpDesX.size()];
                tmpDesXArray = listToArray(tmpDesX, tmpDesXArray);
                Double[] cerXTmp = new Double[cerX.size()];
                Double[] cerYTmp = new Double[containerY.get(ct).size()];


                double[] tmp = Newton_inter_method(
                        listToArray(cerX, cerXTmp),
                        listToArray(containerY.get(ct), cerYTmp), tmpDesXArray);
                if (tmp.length > 0) {
                    for (double value : tmp) {
                        Double v = value;
                        if (v.isInfinite() || v.isNaN()) continue;
                        desY.add(new BigDecimal(value).setScale(3, BigDecimal.ROUND_HALF_UP).doubleValue());
                    }
                    //                    ArrayUtils.addAll(desY, tmp);
                }
//                tmpDesX = new ArrayList<>();
            }
        }

        //Double[] resultArray = new Double[desY.size()];
        double[] resultArray =  desY.stream().mapToDouble(i->i).toArray();
        long end = System.currentTimeMillis();

        //return listToArray(desY, resultArray);
        return resultArray;
    }
    
    /*牛顿插值法*/
    private static double[] Newton_inter_method(Double[] X, Double[] Y, Double X0[]) {
        double[] Y0 = new double[0];
        try {
            int m = X.length;
            int n = X0.length;
            Y0 = new double[n];
            Double[] cp_Y = new Double[m];
            for (int i1 = 0; i1 < n; i1++) {//遍历X0
                double t = 0;
                int j = 0;
                copy_vector(Y, cp_Y);
                int kk = j;
                /*求各级均差*/
                while (kk < m - 1) {
                    kk = kk + 1;
                    for (int i2 = kk; i2 < m; i2++) {
                        cp_Y[i2] = (cp_Y[i2] - cp_Y[kk - 1]) / (X[i2] - X[kk - 1]);
                    }
                }
                /*求插值结果*/
                double temp = cp_Y[0];
                for (int i = 1; i <= m - 1; i++) {
                    double u = 1;
                    int jj = 0;
                    while (jj < i) {
                        u *= (X0[i1] - X[jj]);
                        jj++;
                    }
                    temp += cp_Y[i] * u;
                }
                Y0[i1] = temp;
                //            System.out.println(Y0[i1]);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return Y0;
    }
    /*拷贝向量*/
    private static void copy_vector(Double from[], Double to[]) {
        int k = from.length;
        int k2 = to.length;
        if (k != k2) {
//            System.out.println("the two vector's length is not equal!");
//            System.exit(0);
        }
        for (int i = 0; i < k; i++) {
            to[i] = from[i];
        }
    }

	
}
